package com.jrx.anytxn.accounting.service.impl;

import com.jrx.anytxn.accounting.entity.GaProductSummaryTransition;
import com.jrx.anytxn.accounting.mapper.ext.ExtGaProductSummaryTransitionMapper;
import com.jrx.anytxn.accounting.service.IProductSummaryService;
import com.jrx.anytxn.common.constant.CommonContants;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.uitl.BigDecimalUtils;
import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.entity.BtBatchStatus;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.PrProductTable;
import com.jrx.anytxn.param.mapper.ext.ExtBtBatchStatusMapper;
import com.jrx.anytxn.param.service.product.IProductTableService;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.transaction.config.CustBatchConfig;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.entity.AmAccountMainInfo;
import com.jrx.anytxn.transaction.entity.AmLoanAccountInfo;
import com.jrx.anytxn.transaction.entity.TlGlInterfaceInfo;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlGlInterfaceInfoMapper;
import com.jrx.anytxn.transaction.service.IGlInterfaceService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @program: anytxn-cf-accounting
 * @description: 产品汇总实现类
 * @author: xiaoyu.jing
 * @date: 2019-12-16 10:19
 **/
@Service
public class ProductSummaryServiceImpl implements IProductSummaryService {

    Logger logger = LoggerFactory.getLogger(ProductSummaryServiceImpl.class);


    @Autowired
    private IProductTableService productTableService;
    @Autowired
    private IOrganizationTableService organizationTableService;
    @Autowired
    private ISegmentService iSegmentService;
    @Resource
    private ExtGaProductSummaryTransitionMapper extGaProductSummaryTransitionMapper;
    @Autowired
    private IGlInterfaceService glInterfaceService;
    @Resource
    private ExtTlGlInterfaceInfoMapper extTlGlInterfaceInfoMapper;
    @Resource
    private ExtBtBatchStatusMapper extBtBatchStatusMapper;


    @Override
    public List<GaProductSummaryTransition> summary(Map<String, GaProductSummaryTransition> productSummeryMap, String batchTaskId) throws Exception{
        List<PrProductTable> productTableList = productTableService.findAllForBatch(Constant.STATUS_1);
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        List<GaProductSummaryTransition> transitionList = new ArrayList<>();
        List<TlGlInterfaceInfo> glList = new ArrayList<>();
        Date businessDate = org.getToday();
        productTableList.forEach(prProductTable -> {
                    String productId = prProductTable.getProductId();
                    BigDecimal classify1ImpairmentBal = BigDecimal.ZERO;
                    BigDecimal classify2ImpairmentBal = BigDecimal.ZERO;
                    BigDecimal classify3ImpairmentBal = BigDecimal.ZERO;
                    BigDecimal classify4ImpairmentBal = BigDecimal.ZERO;
                    GaProductSummaryTransition transition = productSummeryMap.get(productId);
                    if (null == transition) {
                        transition = new GaProductSummaryTransition();
                        transition.setProductId(productId);
                        transition.setNomalPrinBal(BigDecimal.ZERO);
                        transition.setOverDuePrinBal(BigDecimal.ZERO);
                        transition.setDeadPrinBal(BigDecimal.ZERO);
                        transition.setBadPrinBal(BigDecimal.ZERO);
                        transition.setNomalIntrBal(BigDecimal.ZERO);
                        transition.setOverDueIntrBal(BigDecimal.ZERO);
                        transition.setPentIntrBal(BigDecimal.ZERO);
                        transition.setCompIntrBal(BigDecimal.ZERO);
                        transition.setAccuIntrBal(BigDecimal.ZERO);
                        transition.setAccuPentIntrBal(BigDecimal.ZERO);
                        transition.setAccuCompIntrBal(BigDecimal.ZERO);
                        transition.setClassify1PrinBal(BigDecimal.ZERO);
                        transition.setClassify2PrinBal(BigDecimal.ZERO);
                        transition.setClassify3PrinBal(BigDecimal.ZERO);
                        transition.setClassify4PrinBal(BigDecimal.ZERO);
                        transition.setOrganizationId(org.getOrganizationId());
                        transition.setTenantId(org.getTenantId());
                    } else {
                        //减值计提
                        if (TransBizConstant.IMPAIRMENT_FLAG_0.equals(prProductTable.getImpairmentFlag())) {
                            boolean flag = true;
                            Date lastDate = null;

                            switch (prProductTable.getImpairmentFrequency()) {
                                case TransBizConstant.IMPAIRMENT_FREQUENCY_0://按日
                                    lastDate = DateUtils.getBeforeDay(businessDate);
                                    break;
                                case TransBizConstant.IMPAIRMENT_FREQUENCY_1://按月
                                    if (DateUtils.compareDateWithLocalDate(DateUtils.getMonthEndTime(businessDate), businessDate) != 0) {
                                        flag = false;
                                        break;
                                    }
                                    lastDate = DateUtils.getLastMonthLastDay(businessDate);
                                    break;
                                case TransBizConstant.IMPAIRMENT_FREQUENCY_2://按季
                                    if (DateUtils.compareDateWithLocalDate(DateUtils.getMonthEndTime(businessDate), businessDate) != 0 || !DateUtils.isQuarterYearly(businessDate)) {
                                        flag = false;
                                        break;
                                    }
                                    lastDate = DateUtils.getLastQuarterYearly(businessDate);
                                    break;
                                case TransBizConstant.IMPAIRMENT_FREQUENCY_3://按年
                                    if (!DateUtils.getMonth(businessDate).equals(TransBizConstant.MONTH_OF_12) || DateUtils.getDay(businessDate).equals(TransBizConstant.DAY_OF_31)) {
                                        flag = false;
                                        break;
                                    }
                                    lastDate = DateUtils.getLastYear(businessDate);
                                    break;
                                default:
                                    flag = false;
                            }

                            //是否到减值计提周期
                            if (flag) {
                                classify1ImpairmentBal = BigDecimalUtils.formatNbr(transition.getClassify1PrinBal().multiply(prProductTable.getClassify1Rate()));
                                classify2ImpairmentBal = BigDecimalUtils.formatNbr(transition.getClassify2PrinBal().multiply(prProductTable.getClassify2Rate()));
                                classify3ImpairmentBal = BigDecimalUtils.formatNbr(transition.getClassify3PrinBal().multiply(prProductTable.getClassify3Rate()));
                                classify4ImpairmentBal = BigDecimalUtils.formatNbr(transition.getClassify4PrinBal().multiply(prProductTable.getClassify4Rate()));
                                BigDecimal classify1ImpairmentLastBal = BigDecimal.ZERO;
                                BigDecimal classify2ImpairmentLastBal = BigDecimal.ZERO;
                                BigDecimal classify3ImpairmentLastBal = BigDecimal.ZERO;
                                BigDecimal classify4ImpairmentLastBal = BigDecimal.ZERO;

                                GaProductSummaryTransition lastTransition = extGaProductSummaryTransitionMapper.selectByDateAndProductId(lastDate, productId);
                                if (null != lastTransition) {
                                    classify1ImpairmentLastBal = Optional.ofNullable(lastTransition.getClassify1ImpairmentBal()).orElse(BigDecimal.ZERO);
                                    classify2ImpairmentLastBal = Optional.ofNullable(lastTransition.getClassify2ImpairmentBal()).orElse(BigDecimal.ZERO);
                                    classify3ImpairmentLastBal = Optional.ofNullable(lastTransition.getClassify3ImpairmentBal()).orElse(BigDecimal.ZERO);
                                    classify4ImpairmentLastBal = Optional.ofNullable(lastTransition.getClassify4ImpairmentBal()).orElse(BigDecimal.ZERO);
                                }

                                String classify1TxnCode = TransBizConstant.TXN_CODE_CLASSIFY1_IMPAIRMENT;
                                String classify2TxnCode = TransBizConstant.TXN_CODE_CLASSIFY2_IMPAIRMENT;
                                String classify3TxnCode = TransBizConstant.TXN_CODE_CLASSIFY3_IMPAIRMENT;
                                String classify4TxnCode = TransBizConstant.TXN_CODE_CLASSIFY4_IMPAIRMENT;

                                BigDecimal subClassify1Bal = classify1ImpairmentBal.subtract(classify1ImpairmentLastBal);
                                if (subClassify1Bal.compareTo(BigDecimal.ZERO) < 0) {
                                    classify1TxnCode = TransBizConstant.TXN_CODE_CLASSIFY1_IMPAIRMENT_REVOCATION;
                                }
                                try {
                                    TlGlInterfaceInfo classify1Gl = glInterfaceService.buildTlGlInterfaceInfo(productId, org.getTenantId(), org.getOrganizationId(), classify1TxnCode,
                                            subClassify1Bal.abs(), TransBizConstant.LOAN_CLASSIFY_1, businessDate);
                                    if (null != classify1Gl) {
                                        glList.add(classify1Gl);
                                    }
                                } catch (TxnException e) {
                                    throw new RuntimeException(e);
                                }

                                BigDecimal subClassify2Bal = classify2ImpairmentBal.subtract(classify2ImpairmentLastBal);
                                if (subClassify2Bal.compareTo(BigDecimal.ZERO) < 0) {
                                    classify2TxnCode = TransBizConstant.TXN_CODE_CLASSIFY2_IMPAIRMENT_REVOCATION;
                                }
                                try {
                                    TlGlInterfaceInfo classify2Gl = glInterfaceService.buildTlGlInterfaceInfo(productId, org.getTenantId(), org.getOrganizationId(), classify2TxnCode,
                                            subClassify2Bal.abs(), TransBizConstant.LOAN_CLASSIFY_2, businessDate);
                                    if (null != classify2Gl) {
                                        glList.add(classify2Gl);
                                    }
                                } catch (TxnException e) {
                                    throw new RuntimeException(e);
                                }

                                BigDecimal subClassify3Bal = classify3ImpairmentBal.subtract(classify3ImpairmentLastBal);
                                if (subClassify3Bal.compareTo(BigDecimal.ZERO) < 0) {
                                    classify3TxnCode = TransBizConstant.TXN_CODE_CLASSIFY3_IMPAIRMENT_REVOCATION;
                                }
                                try {
                                    TlGlInterfaceInfo classify3Gl = glInterfaceService.buildTlGlInterfaceInfo(productId, org.getTenantId(), org.getOrganizationId(), classify3TxnCode,
                                            subClassify3Bal.abs(), TransBizConstant.LOAN_CLASSIFY_3, businessDate);
                                    if (null != classify3Gl) {
                                        glList.add(classify3Gl);
                                    }
                                } catch (TxnException e) {
                                    throw new RuntimeException(e);
                                }

                                BigDecimal subClassify4Bal = classify4ImpairmentBal.subtract(classify4ImpairmentLastBal);
                                if (subClassify4Bal.compareTo(BigDecimal.ZERO) < 0) {
                                    classify4TxnCode = TransBizConstant.TXN_CODE_CLASSIFY4_IMPAIRMENT_REVOCATION;
                                }
                                try {
                                    TlGlInterfaceInfo classify4Gl = glInterfaceService.buildTlGlInterfaceInfo(productId, org.getTenantId(), org.getOrganizationId(), classify4TxnCode,
                                            subClassify4Bal.abs(), TransBizConstant.LOAN_CLASSIFY_4, businessDate);
                                    if (null != classify4Gl) {
                                        glList.add(classify4Gl);
                                    }
                                } catch (TxnException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        }
                    }


                    try {
                        transition.setId(iSegmentService.getId("GaProductSummaryTransition"));
                    } catch (SegmentException e) {
                        throw new RuntimeException(e);
                    }
                    transition.setClassify1ImpairmentBal(classify1ImpairmentBal);
                    transition.setClassify2ImpairmentBal(classify2ImpairmentBal);
                    transition.setClassify3ImpairmentBal(classify3ImpairmentBal);
                    transition.setClassify4ImpairmentBal(classify4ImpairmentBal);
                    transition.setBatchTaskId(batchTaskId);
                    transition.setBussinessDate(businessDate);
                    transition.setUpdateBy(TransBizConstant.SYS_OPRATE);
                    transition.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
                    transitionList.add(transition);

                }
        );
        if (CollectionUtils.isNotEmpty(glList)) {
            extTlGlInterfaceInfoMapper.batchInsertSelective(glList);
        }
        return transitionList;
    }

    @Override
    public GaProductSummaryTransition summary(AmLoanAccountInfo loanAcct, List<AmAccountMainInfo> accountList) throws Exception {
        PrOrganizationTable org = organizationTableService.findByOrId(TransBizConstant.DEFAULT_ORG_ID,loanAcct.getTenantId());
        BtBatchStatus btBatchStatus = extBtBatchStatusMapper.selectByStatusAndJobName(TransBizConstant.BATCH_SATTUS_2, TransBizConstant.CUTOVER_START,
                loanAcct.getTenantId(), org.getNextProcessingDate());
        Date createTimeBt = btBatchStatus.getCreateTime();
        if (loanAcct.getCreateTime().compareTo(createTimeBt) >= 0) {
            return null;
        }

        //分别求出分组产品各个成分的金额
        BigDecimal nomalPrinBal = BigDecimal.ZERO;
        BigDecimal overDuePrinBal = BigDecimal.ZERO;
        BigDecimal deadPrinBal = BigDecimal.ZERO;
        BigDecimal badPrinBal = BigDecimal.ZERO;
        BigDecimal nomalIntrBal = BigDecimal.ZERO;
        BigDecimal overDueIntrBal = BigDecimal.ZERO;


        if (CollectionUtils.isNotEmpty(accountList)) {
            Predicate<AmAccountMainInfo> isPrin = acct -> TransBizConstant.ACCOUNT_TYPE_06.equals(acct.getAccountType());
            Predicate<AmAccountMainInfo> isNomal = acct -> TransBizConstant.ACCOUNTING_PHASE_0.equals(acct.getAccountingPhase());
            Predicate<AmAccountMainInfo> isOverDue = acct -> TransBizConstant.ACCOUNTING_PHASE_1.equals(acct.getAccountingPhase());
            Predicate<AmAccountMainInfo> isDead = acct -> TransBizConstant.ACCOUNTING_PHASE_2.equals(acct.getAccountingPhase());
            Predicate<AmAccountMainInfo> isBad = acct -> TransBizConstant.ACCOUNTING_PHASE_3.equals(acct.getAccountingPhase());

            BigDecimal nomalPrinBalPerLoan = accountList.stream().filter(isPrin).filter(isNomal).map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal overDuePrinBalPerLoan = accountList.stream().filter(isPrin).filter(isOverDue).map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal deadPrinBalPerLoan = accountList.stream().filter(isPrin).filter(isDead).map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal badPrinBalPerLoan = accountList.stream().filter(isPrin).filter(isBad).map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal nomalIntrBalPerLoan = accountList.stream().filter(isPrin.negate()).filter(isNomal).map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal overDueIntrBalPerLoan = accountList.stream().filter(isPrin.negate()).filter(isOverDue).map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);

            nomalPrinBal = nomalPrinBal.add(nomalPrinBalPerLoan);
            overDuePrinBal = overDuePrinBal.add(overDuePrinBalPerLoan);
            deadPrinBal = deadPrinBal.add(deadPrinBalPerLoan);
            badPrinBal = badPrinBal.add(badPrinBalPerLoan);
            nomalIntrBal = nomalIntrBal.add(nomalIntrBalPerLoan);
            overDueIntrBal = overDueIntrBal.add(overDueIntrBalPerLoan);
        }

        Predicate<AmLoanAccountInfo> isNomal = loan -> TransBizConstant.ACCOUNTING_PHASE_0.equals(loan.getAccountingPhase());
        Predicate<AmLoanAccountInfo> isOverDue = loan -> TransBizConstant.ACCOUNTING_PHASE_1.equals(loan.getAccountingPhase());
        Predicate<AmLoanAccountInfo> isDead = loan -> TransBizConstant.ACCOUNTING_PHASE_2.equals(loan.getAccountingPhase());
        Predicate<AmLoanAccountInfo> isBad = loan -> TransBizConstant.ACCOUNTING_PHASE_3.equals(loan.getAccountingPhase());
        Function<AmLoanAccountInfo, BigDecimal> uncastPrin = loan -> loan.getRemainPrincipal().subtract(loan.getPrincipalBalance());

        nomalPrinBal = nomalPrinBal.add(Optional.of(loanAcct).filter(isNomal).map(uncastPrin).orElse(BigDecimal.ZERO));
        overDuePrinBal = overDuePrinBal.add(Optional.of(loanAcct).filter(isOverDue).map(uncastPrin).orElse(BigDecimal.ZERO));
        deadPrinBal = deadPrinBal.add(Optional.of(loanAcct).filter(isDead).map(uncastPrin).orElse(BigDecimal.ZERO));
        badPrinBal = badPrinBal.add(Optional.of(loanAcct).filter(isBad).map(uncastPrin).orElse(BigDecimal.ZERO));
        BigDecimal pentIntrBal = loanAcct.getPenaltyBalance();
        BigDecimal compIntrBal = loanAcct.getCompoundBalance();
        BigDecimal accuIntrBal = loanAcct.getAccruedInterest();
        BigDecimal accuPentIntrBal = loanAcct.getAccruedPenalty();
        BigDecimal accuCompIntrBal = loanAcct.getAccruedCompound();

        //减值计提
        Predicate<AmLoanAccountInfo> isClassify1 = loan -> TransBizConstant.LOAN_CLASSIFY_1.equals(loan.getLoanClassify());
        Predicate<AmLoanAccountInfo> isClassify2 = loan -> TransBizConstant.LOAN_CLASSIFY_2.equals(loan.getLoanClassify());
        Predicate<AmLoanAccountInfo> isClassify3 = loan -> TransBizConstant.LOAN_CLASSIFY_3.equals(loan.getLoanClassify());
        Predicate<AmLoanAccountInfo> isClassify4 = loan -> TransBizConstant.LOAN_CLASSIFY_4.equals(loan.getLoanClassify());
        BigDecimal classify1PrinBal = Optional.of(loanAcct).filter(isClassify1).map(AmLoanAccountInfo::getRemainPrincipal).orElse(BigDecimal.ZERO);
        BigDecimal classify2PrinBal = Optional.of(loanAcct).filter(isClassify2).map(AmLoanAccountInfo::getRemainPrincipal).orElse(BigDecimal.ZERO);
        BigDecimal classify3PrinBal = Optional.of(loanAcct).filter(isClassify3).map(AmLoanAccountInfo::getRemainPrincipal).orElse(BigDecimal.ZERO);
        BigDecimal classify4PrinBal = Optional.of(loanAcct).filter(isClassify4).map(AmLoanAccountInfo::getRemainPrincipal).orElse(BigDecimal.ZERO);

        GaProductSummaryTransition transition = new GaProductSummaryTransition();
        transition.setTenantId(loanAcct.getTenantId());
        transition.setLoanId(loanAcct.getLoanId());
        transition.setOrganizationId(loanAcct.getOrganizationId());
        transition.setNomalPrinBal(nomalPrinBal);
        transition.setOverDuePrinBal(overDuePrinBal);
        transition.setDeadPrinBal(deadPrinBal);
        transition.setBadPrinBal(badPrinBal);
        transition.setNomalIntrBal(nomalIntrBal);
        transition.setOverDueIntrBal(overDueIntrBal);
        transition.setPentIntrBal(pentIntrBal);
        transition.setCompIntrBal(compIntrBal);
        transition.setAccuIntrBal(accuIntrBal);
        transition.setAccuPentIntrBal(accuPentIntrBal);
        transition.setAccuCompIntrBal(accuCompIntrBal);
        transition.setRecordVersionNumber(0);
        transition.setUpdateBy(TransBizConstant.SYS_OPRATE);
        transition.setProductId(loanAcct.getProductId());
        transition.setClassify1PrinBal(classify1PrinBal);
        transition.setClassify2PrinBal(classify2PrinBal);
        transition.setClassify3PrinBal(classify3PrinBal);
        transition.setClassify4PrinBal(classify4PrinBal);
        return transition;
    }
}
